# -*- coding: utf-8 -*-
# @Time    : 2020/5/15
# @Author  : nanjiang.xie
# @File    : RestClient.py

"""
封装基本request类
"""
import json
import hashlib
import requests
#import urlparse
from urllib import parse
import urllib
import dataUtils
import urllib3
from robot.api import logger

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

configData = {
    "app_base_url": "http://152.136.82.136:3023/prod-api/mobile/",          # APP测试环境接口host地址
    "web_base_url": "http://152.136.82.136:9527/stage-api/web/",        # 测试环境web端接口host地址
    "appkey": "7463135097",                                             # 访问CDP服务需要的Appkey；app:大众-品牌APP-ANDROID-UAT
    "secret_key": "3c85076ebb474bed49a7dd90cffd72c7"                    # 访问CDP服务需要的ScrectKey; app:大众-品牌APP-ANDROID-UAT
}


class RestClient:

    def __init__(self):
        """基类初始化
        """
        self.log = logger
        # app端登录参数
        self.app_base_url = configData["app_base_url"]
        self.appkey = configData["appkey"]
        self.secret_key = configData["secret_key"]
        self.headers = {
            "Content-Type": "application/json",
            "x-namespace-code": "cdp-uat-default",
            "x-microservice-name": "api-gateway",
            "Did": "VW_APP_Mate10 Pro_24324327928743324234_Android9.0_v1.2.0"
        }
        self.token = None
        self.username = None
        self.password = None

        # web端登录参数
        self.web_base_url = configData["web_base_url"]
        self.web_token = None
        self.web_username = None
        self.web_password = None
        self.web_headers = {
            "Content-Type": "application/json",
        }

    def one_app_login(self, username, password):
        """C端登录
        - :param username: 【必填】用户名，类型：string
        - :param password: 【必填】用户登录密码，类型：string
        - :return: 无返回体
        """
        self.username = username
        self. password = password
        self._get_token(username=username, password=password)

    def _get_token(self, username, password):
        """获取用户token

        - :param username: 【必填】用户登录名，类型：string
        - :param password: 【必填】用户密码，类型：string
        - :return: 无返回体
        """

        self.username = username
        self.password = password
        # 1.准备headers
        headers = self.headers

        # 2.组装URL
        uri = "one-app/user/public/v1/login"
        # 计算签名
        add_url = self._calc_digital_sign(uri)
        api_url = self.app_base_url + uri + add_url
        # 3.封装请求体
        post_data = {
                    "account": self.username,
                    "password": self.password,
                    "scope": "openid profile mbb"
                }
        post_data = json.dumps(post_data)

        # 下发操作
        try:
            self.log.info("Getting token, headers is: {}".format(headers))
            self.log.info("Getting token, url is: {}".format(api_url))
            self.log.info("Getting token, postdata is: {}".format(post_data))

            response = requests.post(url=api_url, data=post_data, headers=headers)

            self.log.info("Getting token, the status_code is :{}".format(response.status_code))
            assert response.status_code == 200
            content = json.loads(response.content)
            token_type = content['data']['tokenInfo']['tokenType']
            access_token = content['data']['tokenInfo']['accessToken']
            self.token = token_type + " " + access_token
            self.log.info("Token is: {}".format(self.token))
            # 把token加入headers
            self.headers['Authorization'] = self.token
        except Exception as e:
            raise Exception("Get token failed: {}".format(e))

    def get_request(self, url, params=None, **kwargs):
        """封装get操作

        - :param url: 【必填】请求url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + parse.urlencode(params)
        # 分割resource的path，计算签名，返回附加的url
        resource_uri = url.replace(self.app_base_url, "").replace(self.app_base_url, "")
        add_url = self._calc_digital_sign(resource_uri)
        url = url + add_url
        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.headers, verify=False, **kwargs)
            content = json.loads(response.content)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict[u"code"] = response.status_code
        response_dict[u"body"] = content
        return response_dict

    def post_request(self, url, data, **kwargs):
        """封装post操作

        - :param url: 【必填】请求url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 分割resource的path，计算签名，返回附加的url
        resource_uri = url.replace(self.app_base_url, "").replace(self.app_base_url, "")
        add_url = self._calc_digital_sign(resource_uri)
        url = url + add_url
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        data = json.dumps(data)
        try:
            response = requests.post(url=url, data=data, headers=self.headers, verify=False, **kwargs)
            content = json.loads(response.content, encoding="utf-8")
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def post_request_multipart(self, url,  file_path, data=None, **kwargs):
        """提交Multipart/form-data 格式的Post请求
        - :param url: 【必填】url, 类型：string
        - :param file_path:  【必填】文件路径, 类型：string
        - :param data:  【可选】其他请求体, 类型：dict
        - :param kwargs: 【可选】其他必要参数
        - :return: 返回状态码与响应体
        """
        # 分割resource的path，计算签名，返回附加的url
        resource_uri = url.replace(self.app_base_url, "").replace(self.app_base_url, "")
        add_url = self._calc_digital_sign(resource_uri)
        url = url + add_url
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            files = {'file': open(file_path, 'rb')}  # 这里提交的python文件对象(字节)
            del self.headers["Content-Type"]         # header里不能加content-type
            if data is None:
                response = requests.post(url=url, files=files, headers=self.headers, verify=False, **kwargs)
            else:
                data = json.dumps(data)
                response = requests.post(url=url, data=data, files=files, headers=self.headers, verify=False, **kwargs)
            content = json.loads(response.content)
            # 返回状态码与响应体
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        finally:
            self.headers["Content-Type"] = "application/json"

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def put_request(self, url, data, **kwargs):
        """封装put操作

        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 分割resource的path，计算签名，返回附加的url
        resource_uri = url.replace(self.app_base_url, "").replace(self.app_base_url, "")
        add_url = self._calc_digital_sign(resource_uri)
        url = url + add_url
        self.log.info("In Put,last url is: {}".format(url))
        self.log.info("In Put, last headers is: {}".format(self.headers))
        self.log.info("In Put, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            data = json.dumps(data)
            response = requests.put(url=url, data=data, headers=self.headers, verify=False, **kwargs)
            content = json.loads(response.content)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def delete_request(self, url, params, **kwargs):
        """封装delete操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + parse.urlencode(params)
        # 分割resource的path，计算签名，返回附加的url
        resource_uri = url.replace(self.app_base_url, "").replace(self.app_base_url, "")
        add_url = self._calc_digital_sign(resource_uri)
        url = url + add_url
        self.log.info("In Delete, last url is: {}".format(url))
        self.log.info("In Delete, last headers is: {}".format(self.headers))
        try:
            response = requests.delete(url=url, headers=self.headers, verify=False, **kwargs)
        # 返回状态码与响应体
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        return response_dict

    def _calc_digital_sign(self, uri):
        """计算签名

        - :param uri: 【必填】带计算前面的uri, 类型：string
        - :return: 返回附加的url
        """
        # 生成时间戳和nonce
        sign_timestamp = dataUtils.get_time_stamp()
        nonce = dataUtils.rand_uuid()

        # 1.获取资源路径
        resource_uri = uri.split("?")[0]
        resource_uri = resource_uri.replace("test/", "").replace("one-app/", "")

        # 2.获取查询参数
        url_query = parse.urlparse(uri).query

        # 3.添加签名时间，排序
        url_query_dict = dict([(k, v[0]) for k, v in parse.parse_qs(url_query).items()])
        url_query_dict["appkey"] = self.appkey
        url_query_dict["signTimestamp"] = sign_timestamp
        url_query_dict["nonce"] = nonce

        # 排序并生成字符串
        key_sort = sorted(url_query_dict.keys())

        # 4.拼接
        parm_list = []
        for key in key_sort:
            temp = key + '=' + url_query_dict[key]
            parm_list.append(temp)

        # 拼接参数
        catent = "_".join(parm_list)

        # 5.添加应用资源和secret_key
        last_url = resource_uri + "_" + catent + "_" + self.secret_key

        # 计算MD5
        last_url_encode = urllib.request.quote(last_url, safe="")

        my_md5 = hashlib.md5()
        my_md5.update(last_url_encode.encode())
        digital_sign = my_md5.hexdigest()
        self.log.info("digitalSign is:{}".format(digital_sign))

        add_query = {
            "appkey": self.appkey,
            "nonce": nonce,
            "signTimestamp": sign_timestamp,
            "digitalSign": digital_sign
        }
        if len(url_query_dict.keys()) > 3:
            add_url = "&" + parse.urlencode(add_query)
        else:
            add_url = "?" + parse.urlencode(add_query)

        return add_url

    def change_user(self, username, password):
        """切换用户

        - :param username: 【必填】用户名, 类型：string
        - :param password: 【必填】密码, 类型：string
        - :return: 无返回体
        """
        self._get_token(username=username, password=password)

    # ##################################################################
    # ##################################################################
    def one_app_web_login(self, username, password):
        """web端登录
        - :param username: 【必填】用户名，类型：string
        - :param password: 【必填】用户登录密码，类型：string
        - :return: 无返回体
        """
        self.username = username
        self.password = password
        self._web_get_token(username=username, password=password)

    def _web_get_token(self, username, password):
        """web端获取token
        - :param username: 【必填】用户登录名，类型：string
        - :param password: 【必填】用户密码，类型：string
        - :return: 无返回体
        """
        self.web_username = username
        self.web_password = hashlib.md5(password.encode()).hexdigest()  # 密码md5加密

        # 1.准备headers
        headers = self.web_headers
        # 2.组装URL
        uri = "user/login"
        api_url = self.web_base_url + uri
        print(api_url)
        # 3.封装请求体
        post_data = {
            "account": self.web_username,
            "password": self.web_password
        }
        post_data = json.dumps(post_data)

        # 下发操作
        try:
            self.log.info("Getting web token, headers is: {}".format(headers))
            self.log.info("Getting web token, url is: {}".format(api_url))
            self.log.info("Getting web token, postdata is: {}".format(post_data))

            response = requests.post(url=api_url, data=post_data, headers=headers)

            self.log.info("Getting web token, the status_code is :{}".format(response.status_code))
            assert response.status_code == 200
            content = json.loads(response.content)
            self.web_token = content['data']['token']
            self.log.info("Web token is: {}".format(self.web_token))
            # 把token加入headers
            self.web_headers['Authorization'] = self.web_token
        except Exception as e:
            raise Exception("Get web token failed: {}".format(e))

    def get_request_web(self, url, params, **kwargs):
        """封装web端get操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + parse.urlencode(params)
        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.web_headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.content)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def post_request_web(self, url, data, **kwargs):
        """封装post操作

        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.web_headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        data = json.dumps(data)
        try:
            response = requests.post(url=url, data=data, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.content)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def post_request_multipart_web(self, url, data=None, file_path=None, **kwargs):
        """提交Multipart/form-data 格式的Post请求
        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体data, 类型：dict
        - :param file_path:  文【必填】件路径
        - :param kwargs: 【可选】其他必要参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.web_headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            files = {'file': open(file_path, 'rb')}  # 这里提交的python文件对象(字节)
            self.web_headers["Content-Type"] = "multipart/form-data"
            if data is None:
                response = requests.post(url=url, files=files, headers=self.web_headers, verify=False, **kwargs)
            else:
                data = json.dumps(data)
                response = requests.post(url=url, data=data, files=files, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.content)
            # 返回状态码与响应体
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        finally:
            self.headers["Content-Type"] = "application/json"

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def put_request_web(self, url, data, **kwargs):
        """封装put操作

        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Put,last url is: {}".format(url))
        self.log.info("In Put, last headers is: {}".format(self.web_headers))
        self.log.info("In Put, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            data = json.dumps(data)
            response = requests.put(url=url, data=data, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.content)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["body"] = content
        return response_dict

    def delete_request_web(self, url, params, **kwargs):
        """封装delete操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + parse.urlencode(params)
        self.log.info("In Delete, last url is: {}".format(url))
        self.log.info("In Delete, last headers is: {}".format(self.web_headers))
        # 发送请求
        try:
            response = requests.delete(url=url, headers=self.web_headers, verify=False, **kwargs)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        return response_dict


if __name__ == "__main__":
    a = RestClient()
    c = a._get_token(username="18190947413", password="111111")
    print (a.headers)
